import json
import random
import time
from functools import reduce
from hashlib import md5
import urllib.parse
from curl_cffi import requests
from curl_cffi.requests import BrowserType, Response

mixinKeyEncTab = [
    46, 47, 18, 2, 53, 8, 23, 32, 15, 50, 10, 31, 58, 3, 45, 35, 27, 43, 5, 49,
    33, 9, 42, 19, 29, 28, 14, 39, 12, 38, 41, 13, 37, 48, 7, 16, 24, 55, 40,
    61, 26, 17, 0, 1, 60, 51, 30, 4, 22, 25, 54, 21, 56, 59, 6, 63, 57, 62, 11,
    36, 20, 34, 44, 52
]


def getWbiKeys() -> tuple[str, str]:
    '获取最新的 img_key 和 sub_key'
    resp = requests.get('https://api.bilibili.com/x/web-interface/nav',
                        impersonate=random.choice(list(map(lambda x: x.value, BrowserType))))
    resp.raise_for_status()
    json_content = resp.json()
    img_url: str = json_content['data']['wbi_img']['img_url']
    sub_url: str = json_content['data']['wbi_img']['sub_url']
    img_key = img_url.rsplit('/', 1)[1].split('.')[0]
    sub_key = sub_url.rsplit('/', 1)[1].split('.')[0]
    return img_key, sub_key


img_key, sub_key = getWbiKeys()


def getMixinKey(orig: str):
    '对 imgKey 和 subKey 进行字符顺序打乱编码'
    return reduce(lambda s, i: s + orig[i], mixinKeyEncTab, '')[:32]


def encWbi(params: dict, _img_key: str, _sub_key: str) -> dict:
    '为请求参数进行 wbi 签名'
    mixin_key = getMixinKey(_img_key + _sub_key)
    curr_time = round(time.time())
    params['wts'] = curr_time  # 添加 wts 字段
    params = dict(sorted(params.items()))  # 按照 key 重排参数
    # 过滤 value 中的 "!'()*" 字符
    params = {
        k: ''.join(filter(lambda chr: chr not in "!'()*", str(v)))
        for k, v
        in params.items()
    }
    query = urllib.parse.urlencode(params)  # 序列化参数
    wbi_sign = md5((query + mixin_key).encode()).hexdigest()  # 计算 w_rid
    params['w_rid'] = wbi_sign
    return params


def get_query(**parameters: dict):
    """
    获取签名后的查询参数
    """
    signed_params = encWbi(
        params=parameters,
        _img_key=img_key,
        _sub_key=sub_key
    )
    query = urllib.parse.urlencode(signed_params)
    return query


## 加密方法https://github.com/SocialSisterYi/bilibili-API-collect/blob/4645c1ef9a98cb7b87875164f83d94f3ecbbc92b/docs/misc/sign/wbi.md?plain=1#L119
def getReplyResp(oid: int, cursor: int) -> Response:
    params = {
        'oid': oid,
        'type': 1,  # 评论类型，不同的动态下方类型不同
        'mode': 2,  # 2是最新评论 3是热门评论
        'pagination_str': json.dumps(
            {"offset": json.dumps({"type": 3, "direction": 1, "Data": {"cursor": cursor}}, separators=(',', ':'))},
            separators=(',', ':')),  # 去除默认json.dumps带的空格
        'plat': 1,
        'web_location': 1315875,
    }
    query = get_query(**params)
    url = f'https://api.bilibili.com/x/v2/reply/wbi/main?{query}'
    resp = requests.get(url, impersonate=random.choice(list(map(lambda x: x.value, BrowserType))))
    print(url)
    print(resp.json())
    return resp


def getSubReplyResp(oid: int, root: int, pn: int):
    url = "https://api.bilibili.com/x/v2/reply/reply"
    params = {
        'oid': oid,
        'type': '1',
        'root': root,
        'ps': 10,
        'pn': pn,
        'web_location': '333.788'
    }
    resp = requests.get(url, params=params, impersonate=random.choice(list(map(lambda x: x.value, BrowserType))))
    print(url + '?' + urllib.parse.urlencode(params))
    print(resp.json())
    return resp


if __name__ == '__main__':
    getSubReplyResp(1750499714, 206931906560, 4)
